package com.bigknow.appstore.web.framework.security;

import com.bigknow.appstore.web.framework.util.GlobalConstant;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 继承shiro的FormAuthenticationFilter 加入对验证码的校验支持
 * Created by Administrator on 2015/4/7.
 */
public class CaptchaFormAuthenticationFilter extends FormAuthenticationFilter {

    private static final Logger logger = LoggerFactory.getLogger(CaptchaFormAuthenticationFilter.class);


    protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
        UsernamePasswordToken token = (UsernamePasswordToken) createToken(request, response);
        if (token == null) {
            String msg = "createToken method implementation returned null. A valid non-null AuthenticationToken " +
                    "must be created in order to execute a login attempt.";
            throw new IllegalStateException(msg);
        }

        try {
            //检验验证码是否正确
            //CaptchaValidation((HttpServletRequest) request);
            //不采用验证码方式
            withNoCaptchaValidation((HttpServletRequest) request);
            Subject subject = getSubject(request, response);
            subject.login(token);
            return onLoginSuccess(token, subject, request, response);
        } catch (AuthenticationException e) {
            return onLoginFailure(token, e, request, response);
        }
    }

    /**
     * 验证输入的验证码是否正确
     *
     * @param request
     * @return
     */
    private void CaptchaValidation(HttpServletRequest request) {
        String code = (String) request.getSession().getAttribute(GlobalConstant.DEFAULT_CAPTCHA_PARAM);
        if (StringUtils.isNotBlank(code)) {
            code = code.toLowerCase();
        }
        String submitCode = request.getParameter(GlobalConstant.DEFAULT_CAPTCHA_PARAM);
        if (StringUtils.isNotBlank(submitCode)) {
            submitCode = submitCode.toLowerCase().trim().toString();
        }
        if (StringUtils.isBlank(submitCode) || StringUtils.isBlank(code) || !code.equals(submitCode)) {
            throw new CaptchaValidationException();
        }
    }

    /**
     * 注册页面需要,直接屏蔽掉验证码校验
     *
     * @param request
     */
    private void withNoCaptchaValidation(HttpServletRequest request) {
        //我啥都不干
    }

    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject,
                                     ServletRequest request, ServletResponse response) throws Exception {
        //这厮需改过后的方法,原方法在webUtil.redirectToSavedRequest(request, response, getSuccessUrl());
        redirectToSavedRequest(request, response, getSuccessUrl());
        return false;
    }

    /**
     * shiro url会记录,所以如果没有登陆的时候访问一个页面,登陆后会自动跳转过去,
     * 这样的话json路径就会被显示出来,但我们需要直接返回首页,所以去掉了判断部分
     *
     * @param request
     * @param response
     * @param fallbackUrl
     * @throws IOException
     */
    public void redirectToSavedRequest(ServletRequest request, ServletResponse response, String fallbackUrl)
            throws IOException {
        String successUrl = null;
        boolean contextRelative = true;
        if (successUrl == null) {
            successUrl = fallbackUrl;
        }

        if (successUrl == null) {
            throw new IllegalStateException("Success URL not available via saved request or via the " +
                    "successUrlFallback method parameter. One of these must be non-null for " +
                    "issueSuccessRedirect() to work.");
        }

        Map<String, String> params = new HashMap<>();
        params.put("target", request.getParameter("target"));
        params.put("cluster", request.getParameter("cluster"));
        //oauth部分需要的参数值
        params.put("login_type", request.getParameter("login_type"));
        params.put("client_id", request.getParameter("client_id"));
        params.put("state", request.getParameter("state"));
        params.put("redirect_uri", request.getParameter("redirect_uri"));
        WebUtils.issueRedirect(request, response, successUrl, params, contextRelative);
    }

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        Subject subject = getSubject(request, response);

        //如果 isAuthenticated 为 false 证明不是登录过的，同时 isRememberd 为true 证明是没登陆直接通过记住我功能进来的
        if (!subject.isAuthenticated() && subject.isRemembered()) {

            //获取session看看是不是空的
            Session session = subject.getSession(true);

            //随便拿session的一个属性来看session当前是否是空的，我用userId，你们的项目可以自行发挥
            if (session.getAttribute("userId") == null) {

                //如果是空的才初始化，否则每次都要初始化，项目得慢死
                //这边根据前面的前提假设，拿到的是username
                String username = subject.getPrincipal().toString();
            }
        }

        //这个方法本来只返回 subject.isAuthenticated() 现在我们加上 subject.isRemembered() 让它同时也兼容remember这种情况
        return subject.isAuthenticated() || subject.isRemembered();
    }
}
